package jxta.chat.module;

import java.io.IOException;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.List;

import jxta.chat.PipeHolder;
import jxta.chat.entities.AbstractMessage;
import jxta.chat.entities.MessageFactory;
import jxta.chat.entities.MessageParams;
import jxta.chat.events.JxtaChatEvent;
import jxta.chat.events.JxtaChatListener;
import jxta.chat.util.Constants.MessageTypes;
import jxta.test.JxtaManager;
import net.jxta.endpoint.Message;
import net.jxta.peergroup.PeerGroup;
import net.jxta.pipe.PipeMsgEvent;
import net.jxta.pipe.PipeMsgListener;
import net.jxta.pipe.PipeService;
import net.jxta.protocol.PipeAdvertisement;
import net.jxta.util.JxtaBiDiPipe;
import net.jxta.util.JxtaServerPipe;

public class PipeModuleManager extends AbstractModuleManager implements ModulePipeListener{

	private JxtaServerPipe serverPipe = null;
	private PipeServerThread serverThread = null;
	//private ListenerNotifier notifier;
	
	// TODO Move it to the super class
	protected List<JxtaChatListener> chatListeners = new ArrayList<JxtaChatListener>(); 
	
	public PipeModuleManager(String name, String type){
		super(name, type);
	}
	
	public void addChatListener(JxtaChatListener listener){
		chatListeners.add(listener);
	}
	
	private void notifyChatListener(JxtaChatEvent event){
		synchronized (chatListeners) {		
			for (JxtaChatListener listener : chatListeners){
				listener.jxtaChatEvent(event);
			}
		}
	}
	
	@Override
	public PipeAdvertisement initialize(PeerGroup pg) {
        // create a new serverPipe instance
        try {
            this.serverPipe = new JxtaServerPipe(pg, JxtaManager.getPipeAdv(pg, moduleName, PipeService.UnicastType, null));            
        } catch (IOException ioe) {
            ioe.printStackTrace(System.out);
        }

        // Create a new thread that accepts connections
        // coming in on the newly created serverPipe
        if (this.serverPipe != null) {
            try {
                this.serverPipe.setPipeTimeout(0);
            } catch (SocketException se) {
                se.printStackTrace(System.out);
            }

            this.serverThread = new PipeServerThread(pg, this.serverPipe,
                    getClass().getName() + ":mySkypeServerPipe");
            serverThread.start();
        }		
        
        return this.serverPipe.getPipeAdv();
	}
	
	public PipeAdvertisement getPipeAdv(){
		return serverPipe != null ? serverPipe.getPipeAdv() : null;
	}
	
	/**
	 * The class waits for pipe events
	 *
	 */
	private class PipeServerThread extends Thread{
		private PeerGroup pg = null;
        private JxtaServerPipe serverPipe = null;
        private boolean stopped = false;

        /**
         * Create a new ServerThread object
         *
         * @param pg   the PeerGroup in which this listener operates
         * @param name the name of the thread
         */
        protected PipeServerThread(PeerGroup pg, JxtaServerPipe serverPipe,
                               String name) {
            super(name);

            this.pg = pg;
            this.serverPipe = serverPipe;
            setDaemon(true);
        }

        public void stopServer() {
            stopped = true;
            if (this.serverPipe != null)
                if (!this.serverPipe.isClosed())
                    try {
                        this.serverPipe.close();

                    } catch (IOException e) {
                        e.printStackTrace();
                    }

        }

       /**
        * run until stop is marked as true and waits for messages
        * on the pipe
        */
        public void run() {
            JxtaBiDiPipe pipe = null;

            while (!stopped) {
                // wait until a connection request is received
                try {
                	System.out.println("Start listen to BiDiPipe");
                	
                    pipe = this.serverPipe.accept();
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                }
                
                /*System.out.println("Got a message in bidiserverpipe. pipe adv: " + pipe.getPipeAdvertisement());
                System.out.println("Got a message in bidiserverpipe. remote pipe adv: " + pipe.getRemotePipeAdvertisement());
                System.out.println("Got a message in bidiserverpipe. remote peer adv: " + pipe.getRemotePeerAdvertisement());*/

                // if a connection request is received,
                // pass it on to the registered DialogPipeListeners
                if (pipe != null) {

                	pipe.setMessageListener(new EventListener());
                }
                
                PipeAdvertisement adv = pipe.getRemotePipeAdvertisement();
                adv.setType(PipeService.UnicastType);
                
                // Add the new discovered peer pipe
                //PipeHolder.getInstance().addPipe(adv, pg, pipe.getRemotePeerAdvertisement().getName());
                PipeHolder.getInstance().addPipe(pipe.getRemotePeerAdvertisement().getName(), pipe);
                
                MessageParams mp = new MessageParams(pipe.getRemotePeerAdvertisement().getName());
                AbstractMessage am = MessageFactory.getInstance().getMessageClass(MessageTypes.USER_DISCOVERED);
                am.createMessage(mp);
                JxtaChatEvent event = new JxtaChatEvent(am);
                
                notifyChatListener(event);
            }
            //System.out.println("shutdown");
        }
    }

	// TODO Check if i realy need that this class will be the listener class for all pipes
	
	private class EventListener implements PipeMsgListener{

		//@Override
		public void pipeMsgEvent(PipeMsgEvent arg0) {
			
			//System.out.println("In PipeModuleManager. Got a message");
			
			AbstractMessage msg = MessageFactory.getInstance().getMessageClass(arg0.getMessage());
			
			if (msg != null){
				notifyChatListener(new JxtaChatEvent(msg));
			}
			/*notifier = new ListenerNotifier(arg0);
			notifier.start();*/
		}
	}
	
	// TODO Remove the class
	
	/*private class ListenerNotifier extends Thread{

		private PipeMsgEvent event = null;
		
		public ListenerNotifier(PipeMsgEvent event){
			this.event = event;
		}
		
		public void setEvent(PipeMsgEvent event){
			this.event = event;
		}
		
		@Override
		public void run() {
			System.out.println("In PipeModuleManager. Got a message");
			
			if (this.event == null){
				return;
			}
			
			AbstractMessage msg = MessageFactory.getInstance().getMessageClass(this.event.getMessage());
			
			if (msg != null){
				notifyChatListener(new JxtaChatEvent(msg));
			}
		}
		
	}*/
}
